# -*- coding: utf-8 -*-
# @Time    : 2021/9/3 14:31
# @Author  : huangwei
# @File    : inotify.py
# @Software: PyCharm
import threading
import traceback
import pika
from watchdog.observers import Observer
from watchdog.events import *
from functions import exist_watch_path, get_current_time, psnr, create_dir, delete_dir
from file_type import get_file_type
from img_functions import img_extract_watermark, img_insert_watermark
from method import get_video_param
from video_functions import video_extract_watermark, video_add_visual_watermark, video_insert_watermark

WATCH_PATH = "D:\Data/tpsoft\watermark\data"
WATERMARK_PATH = 'D:\Data\watermark\images\watermark.png'  # 水印路径
BLACK_WATERMARK_PATH = "/home/data/watermark/blank.png"  # 空白水印路径

# 用于加水印的输入输出文件路径
IMAGE_PATH = "%s/picture/origin" % WATCH_PATH
VIDEO_PATH = "%s/video/origin" % WATCH_PATH
IMAGE_TARGET_PATH = "%s/picture/target" % WATCH_PATH
VIDEO_TARGET_PATH = "%s/video/target" % WATCH_PATH

# 传入文件目录，来判断是否存在水印，如果存在则解出水印，不存在则解出一张空白图
SOLUTION_PATH = "%s/solution" % WATCH_PATH
SOLUTION_ORIGIN_IMG_PATH = '%s/picture/origin' % SOLUTION_PATH
SOLUTION_ORIGIN_VIDEO_PATH = '%s/video/origin' % SOLUTION_PATH
SOLUTION_TARGET_IMG_PATH = '%s/picture/target' % SOLUTION_PATH
SOLUTION_TARGET_VIDEO_PATH = '%s/video/target' % SOLUTION_PATH

# rabbitmq 参数
HOST = '123.60.39.193'
PORT = 5672
VIRTUAL_HOST = '/'
USERNAME = 'w1'
PASSWORD = 'w1'
QUEUE_NAME = 'watermark_queue9'

# 可选的音视频种类
image_type = ['jpg', 'png', 'bmp', ]
video_type = ['mp4', 'wav', 'flv', 'avi', ]

# 判断watch path 是否存在
exist_watch_path(WATCH_PATH)

# mq连接和队列声明
credentials = pika.PlainCredentials(USERNAME, PASSWORD)  # mq用户名和密码
# 虚拟队列需要指定参数 virtual_host，如果是默认的可以不填。
product_connection = pika.BlockingConnection(
    pika.ConnectionParameters(host=HOST, port=PORT, heartbeat=0, virtual_host=VIRTUAL_HOST, credentials=credentials))
product_channel = product_connection.channel()
# 声明消息队列，消息将在这个队列传递，如不存在，则创建
product_channel.queue_declare(queue=QUEUE_NAME)

# 虚拟队列需要指定参数 virtual_host，如果是默认的可以不填。
consum_connection = pika.BlockingConnection(
    pika.ConnectionParameters(host=HOST, port=PORT, heartbeat=0, virtual_host=VIRTUAL_HOST, credentials=credentials))
consum_channel = consum_connection.channel()
# 声明消息队列，消息将在这个队列传递，如不存在，则创建
consum_channel.queue_declare(queue=QUEUE_NAME)


class FileEventHandler(FileSystemEventHandler):
    def __init__( self ):
        FileSystemEventHandler.__init__(self)

    # def on_any_event( self, event ):
    #     print("监听到事件：", event.event_type)

    # 只监听文件的重命名操作，将文件名添加到队列中
    def on_moved( self, event ):
        if not event.is_directory:
            print("file moved from {0} to {1}".format(event.src_path, event.dest_path))
            message = event.dest_path
            product_channel.basic_publish(exchange='', routing_key=QUEUE_NAME, body=message)


def insert_watermark( filepath ):
    dir_name = os.path.dirname(filepath)  # 路径名
    file_name = os.path.basename(filepath)  # 文件名
    (name, extension) = os.path.splitext(file_name)  # 分离文件名和后缀
    kind = get_file_type(filepath)
    print("文件类型为：", kind)

    if os.path.normcase(dir_name) == os.path.normcase(IMAGE_PATH):
        if kind in image_type:
            # 判断图片是否已经加过水印，如果已经加过，则提取出水印，否则加水印
            extract_watermark_path = "{0}/{1}_dark.png".format(IMAGE_TARGET_PATH, name)
            exist_watermark = img_extract_watermark(filepath, extract_watermark_path)
            if not exist_watermark:
                exist_watermark = img_extract_watermark(filepath, extract_watermark_path, location=(0, 0))

            if not exist_watermark:
                print("该图片中不存在水印：", filepath)
                print("往图片中添加水印!")

                output_filepath = "{0}/{1}_darkmark{2}".format(IMAGE_TARGET_PATH, name, extension)
                img_insert_watermark(filepath, WATERMARK_PATH, output_filepath)

                psnr_value = psnr(filepath, output_filepath)

                if psnr_value < 30:
                    print("这种方式插入的水印效果不好，psnr的值为：", psnr_value)
                elif psnr_value > 43:
                    img_insert_watermark(filepath, WATERMARK_PATH, output_filepath, (0, 0))
                    psnr_value = psnr(filepath, output_filepath)
                print("psnr value is :", psnr_value)
                print("添加水印的图片存储到：", output_filepath)
        else:
            print("该文件为不符合要求的图片类型：", filepath)

    elif os.path.normcase(dir_name) == os.path.normcase(VIDEO_PATH):
        if kind in video_type:
            # 判断输入视频是否已经加过了水印，如果已经加过，则提取出水印，否则加水印
            # 创建临时文件夹
            tmp_directory = "{0}/{1}_tmp".format(VIDEO_TARGET_PATH, name)
            create_dir(tmp_directory)

            extract_watermark_path = "{0}/{1}_dark.png".format(VIDEO_TARGET_PATH, name)
            exist_watermark = video_extract_watermark(filepath, extract_watermark_path, WATERMARK_PATH, tmp_directory)
            # exist_watermark = False

            if not exist_watermark:
                # 插入可见水印
                print("7.视频中不存在水印，往视频中插入可见水印！")
                output_filepath = "{0}/{1}_mark.mp4".format(VIDEO_TARGET_PATH, name)
                video_add_visual_watermark(filepath, WATERMARK_PATH, output_filepath, tmp_directory)

                """插入数字水印"""
                # 输出文件 应该是  mp4 类型
                video_param = get_video_param(filepath)
                duration = video_param['duration']
                output_filepath = "{0}/{1}_darkmark.mp4".format(VIDEO_TARGET_PATH, name)
                print("duration:", duration)
                if duration < 1.5:
                    os.system("cp {0} {1}".format(filepath, output_filepath))
                    print("复制文件：", filepath, output_filepath)
                else:
                    print("11.往视频中插入数字水印！")

                    video_insert_watermark(filepath, WATERMARK_PATH, output_filepath, tmp_directory)

            # 删除临时文件夹
            delete_dir(tmp_directory)

        else:
            print("传入的视频不符合要求的视频类型！")

    elif os.path.normcase(dir_name) == os.path.normcase(SOLUTION_ORIGIN_IMG_PATH):
        """ 用于单独从图片中解出水印 """
        if kind in image_type:
            # 判断输入图片是否存在水印，如果存在，则提取出水印，否则将复制空白图
            print("输入图片是否存在水印，如果存在，则提取出水印，否则将复制空白图")
            extract_watermark_path = "{0}/{1}_dark.png".format(SOLUTION_TARGET_IMG_PATH, name)
            exist_watermark = img_extract_watermark(filepath, extract_watermark_path)
            # 判断水印是否加在 (0, 0) 位置
            if not exist_watermark:
                exist_watermark = img_extract_watermark(filepath, extract_watermark_path, location=(0, 0))

            if not exist_watermark:
                # 复制空白水印过来
                os.system("cp {0} {1}".format(BLACK_WATERMARK_PATH, extract_watermark_path))
                print("图片中不存在水印！复制空白图片到：", extract_watermark_path)

        else:
            print("传入的图片不符合要求的图片类型！")

    elif os.path.normcase(dir_name) == os.path.normcase(SOLUTION_ORIGIN_VIDEO_PATH):
        if kind in video_type:
            # 判断输入视频是否存在水印
            # 创建临时文件夹
            tmp_directory = "{0}/{1}_tmp".format(VIDEO_TARGET_PATH, name)
            create_dir(tmp_directory)

            print("判断输入视频是否存在水印，如果存在，则提取出水印，否则将复制空白图")
            extract_watermark_path = "{0}/{1}_dark.png".format(SOLUTION_TARGET_VIDEO_PATH, name)
            exist_watermark = video_extract_watermark(filepath, extract_watermark_path, WATERMARK_PATH, tmp_directory)

            if not exist_watermark:
                os.system("cp {0} {1}".format(BLACK_WATERMARK_PATH, extract_watermark_path))
                print("视频中不存在水印！复制空白图片到：", extract_watermark_path)

            # 删除临时文件夹
            delete_dir(tmp_directory)
        else:
            print("传入的视频不符合要求的视频类型！")


def callback( ch, method, properties, body ):
    try:
        ch.basic_ack(delivery_tag=method.delivery_tag)

        # 在这里进行水印的处理
        filepath = body.decode()
        print("从消息队列中取出的文件路径进行处理:", filepath)
        print("start time:", get_current_time())

        insert_watermark(filepath)

        print("finish time:", get_current_time())
    except Exception as e:
        print("there find a exception:", e)
        print(traceback.print_exc())
        print("program will continue running!")


def consum():
    print("监听消息队列的线程:", threading.current_thread().getName())
    # 告诉rabbitmq，用callback来接收消息
    consum_channel.basic_consume(QUEUE_NAME, callback)
    # 开始接收信息，并进入阻塞状态，队列里有信息才会调用callback进行处理
    consum_channel.start_consuming()


if __name__ == '__main__':
    # 监听消息队列的线程
    consum_thread = threading.Thread(target=consum)
    consum_thread.start()

    # 监控文件夹的变化并将增加的文件名上传到队列中
    observer = Observer()
    event_handler = FileEventHandler()
    # True：监控文件
    observer.schedule(event_handler, WATCH_PATH, True)
    observer.start()
    observer.join()
